﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;

namespace Ingenious.Utility
{
    /// <summary>
    /// Allows raising of property changed events using a lambda expression
    /// rather than a plain text string (for refactoring)
    /// </summary>
    public class PropertyChangedHelper<TSource>
        where TSource : INotifyPropertyChanged
    {
        private static readonly string PropertyChangedEventName = "PropertyChanged";
        private MulticastDelegate m_propertyChangedDelegate;

        private TSource m_parent;

        #region Object Lifetime
        public PropertyChangedHelper(TSource parent)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }

            m_parent = parent;

            // Cache property change event multicast delegate
            m_propertyChangedDelegate = (MulticastDelegate)typeof(TSource).GetField(PropertyChangedEventName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetValue(parent);
        }
        #endregion

        public void OnPropertyChanged(Expression<Func<TSource>> propertyLambda)
        {
            MemberExpression memberExpression = propertyLambda.Body as MemberExpression;

            if (memberExpression == null)
            {
                throw new ArgumentException("Not a valid property selector expression");
            }

            OnPropertyChanged(memberExpression.Member.Name);
        }

        private void OnPropertyChanged(string propertyName)
        {
            foreach (EventHandler<PropertyChangedEventArgs> propertyChangedHandler in m_propertyChangedDelegate.GetInvocationList())
            {
                propertyChangedHandler.Invoke(m_parent, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
